<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>canvas撤销与恢复</title>
</head>
<style>
</style>

<body>
  <canvas id="cvs" width="800" height="500" style="background-color:#eee;"></canvas>
  <h1>ctrl+z | ctrl+y</h1>
  <script>
    const cvs = document.getElementById('cvs')
    const ctx = cvs.getContext('2d')
    let saveData = []
    let revokeData = []
    let isDrawing = false
    cvs.addEventListener('mousedown', e => {
      isDrawing = true
      ctx.moveTo(e.pageX, e.pageY)
      saveData.push({
        move: [e.pageX, e.pageY],
        line: []
      })
    })
    cvs.addEventListener('mousemove', e => {
      if (isDrawing) {
        ctx.lineWidth = 10
        ctx.lineTo(e.pageX, e.pageY)
        ctx.stroke()
        saveData[saveData.length - 1].line.push([e.pageX, e.pageY])
      }
    })
    cvs.addEventListener('mouseup', e => {
      isDrawing = false
    })
    document.onkeyup = e => {
      const key = e.key.toLocaleLowerCase()
      if (e.ctrlKey && (key === 'z' || key === 'y')) {
        if (key === 'z') {
          saveData.length && revokeData.push(saveData.pop())
        } else if (key === 'y') {
          revokeData.length && saveData.push(revokeData.pop())
        }
        ctx.clearRect(0, 0, cvs.width, cvs.height)
        ctx.beginPath()
        saveData.forEach(v => {
          ctx.moveTo(v.move[0], v.move[1])
          v.line.forEach(k => {
            ctx.lineTo(k[0], k[1])
          })
          ctx.stroke()
        })
      }
    }
  </script>
</body>

</html>